/*
 * Copyright (C) 2005 David Orme <djo@coconut-palm-software.com>
 * 
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 * 
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     David Orme     - Initial API and implementation
 *     The Pampered Chef - Generalized
 */
package org.eclipse.nebula.widgets.compositetable;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;

/**
 * An abstract row class making it easy to implement a table where the whole
 * row is selected at once.
 *
 * @author djo
 */
public abstract class AbstractSelectableRow extends Composite implements
		TraverseListener, FocusListener, MouseListener, IRowFocusListener,
		IRowContentProvider, KeyListener {

	private Display display = Display.getCurrent();

	private Color LIST_BACKGROUND = display
			.getSystemColor(SWT.COLOR_LIST_BACKGROUND);

	private Color LIST_FOREGROUND = display
			.getSystemColor(SWT.COLOR_LIST_FOREGROUND);

	private Color LIST_SELECTION = display
			.getSystemColor(SWT.COLOR_LIST_SELECTION);

	private Color LIST_SELECTION_TEXT = display
			.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT);

	private Color LIST_SELECTION_NOFOCUS = display
			.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);

	private Color LIST_SELECTION_TEXT_NOFOCUS = display
			.getSystemColor(SWT.COLOR_LIST_FOREGROUND);

	protected List labels;

	public AbstractSelectableRow(Composite parent, int style) {
		super(parent, style);
		addTraverseListener(this);
		addFocusListener(this);
		addMouseListener(this);
		addKeyListener(this);
	}

	/**
	 * This method initializes this
	 * 
	 */
	private void initialize() {
		this.labels = new ArrayList();
		for (int i = 0; i < getColumnCount(); i++) {
			Label label = new Label(this, SWT.NONE);
			this.labels.add(label);
			label.addMouseListener(this);
		}
	}

	public List getLabelsList() {
		return this.labels;
	}

	private void setRowColor(Color foreground, Color background) {
		setBackground(background);
		setForeground(foreground);
		Control[] children = getChildren();
		for (int i = 0; i < children.length; i++) {
			children[i].setBackground(background);
			children[i].setForeground(foreground);
		}
	}

	// Event handlers ----------------------------------------------------------

	public void keyTraversed(TraverseEvent e) {
		// NOOP: this just lets us receive focus from SWT
	}

	public void focusGained(FocusEvent e) {
		setRowColor(LIST_SELECTION_TEXT, LIST_SELECTION);
		selected = true;
		setSelection(model);
	}

	protected void setSelection(Object model) {
		// noop
	}

	private boolean selected = false;

	private boolean inactiveSelected = false;

	public void focusLost(FocusEvent e) {
		if (selected) {
			setRowColor(LIST_SELECTION_TEXT_NOFOCUS, LIST_SELECTION_NOFOCUS);
			inactiveSelected = true;
		}
	}

	public void depart(CompositeTable sender, int currentObjectOffset,
			Control row) {
		if(row == this && selected) {
			deselectRow();
		}
	}

	public void arrive(CompositeTable sender, int currentObjectOffset,
			Control newRow) {
		// NO OP
	}

	public void refresh(CompositeTable sender, int currentObjectOffset,
			Control row) {
		if (row == this && inactiveSelected) {
			deselectRow();
		}
	}

	private void deselectRow() {
		setRowColor(LIST_FOREGROUND, LIST_BACKGROUND);
		selected = false;
		inactiveSelected = false;
	}

	public boolean requestRowChange(CompositeTable sender,
			int currentObjectOffset, Control row) {
		// Always ok to change rows
		return true;
	}

	public void mouseDown(MouseEvent e) {
		setFocus();
	}

	/**
	 * Clients should override to implement their double-click behavior.
	 * 
	 * {@inheritDoc}
	 */
	public void mouseDoubleClick(MouseEvent e) {
		// noop
	};

	public void mouseUp(MouseEvent e) {
		// noop
	}

	private Object model = null;

	public void setModel(Object object) {
		this.model = object;
	}

	public Object getModel() {
		return model;
	}

	public void setMenu(Menu menu) {
		super.setMenu(menu);
		for (Iterator labelIter = labels.iterator(); labelIter.hasNext();) {
			Label label = (Label) labelIter.next();
			label.setMenu(menu);
		}
	}

	public void keyPressed(KeyEvent e) {
		// NOOP
	}

	public void keyReleased(KeyEvent e) {
		// Don't want to hard-code key bindings.  Clients override this method?
		
//	      if (e.character == SWT.DEL && e.stateMask == 0) {
//	          deleteSelectedObject();
//	       }
//	       if (e.character == SWT.CR && e.stateMask == 0) {
//	          runDoubleClickOpenAction();
//	       }
	}
	
	private int columnCount = -1;

	/**
	 * Method setColumnCount.  Sets the number of columns in the row.  This
	 * method must be called <b>exactly</b> once in the overridden constructor.
	 * 
	 * @param columnCount The number of columns in the row.
	 */
	public void setColumnCount(int columnCount) {
		if (this.columnCount > -1) {
			throw new IllegalArgumentException("Cannot setColumnCount more than once");
		}
		this.columnCount = columnCount;
		initialize();
		setRowColor(LIST_FOREGROUND, LIST_BACKGROUND);
	}
	
	private int getColumnCount() {
		return columnCount;
	}

}
